﻿//
//SpingManager.cs for unity-chan!
//
//Original Script is here:
//ricopin / SpingManager.cs
//Rocket Jump : http://rocketjump.skr.jp/unity3d/109/
//https://twitter.com/ricopin416
//
//Revised by N.Kobayashi 2014/06/24
//           Y.Ebata
//
using UnityEngine;
using System.Collections;
using System.Collections.Generic;

namespace UnityChan
{
    public class SpringManager : MonoBehaviour
    {
        //Kobayashi
        // DynamicRatio is paramater for activated level of dynamic animation 
        public float dynamicRatio = 1.0f;

        //Ebata
        public float pullForce;
        public AnimationCurve pullCurve;
        public float stiffnessForce;
        public AnimationCurve stiffnessCurve;
        public float dragForce;
        public AnimationCurve dragCurve;
        public List<SpringBone2> springBones;
        public float toCurrentFactor = 1f;
        public Vector3 boneAxis = new Vector3(0.0f, -1.0f, 0.0f);
        public SpringCollider[] colliders;
        public Transform colidersContainer;
        public Vector3 gravity;
        public Collider[] unityCollider;
        public float skinThickness;
        public float rayOs;
        private void Awake()
        {
            colliders = colidersContainer.GetComponentsInChildren<SpringCollider>();
            unityCollider = colidersContainer.GetComponentsInChildren<Collider>();
            GetComponentsInChildren(springBones);
            for (int i = 0; i < springBones.Count; i++)
            {
                if (i == springBones.Count - 1)
                    springBones[i].enabled = false;
                else
                    springBones[i].child = springBones[i + 1].transform;
            }
        }
        void Start()
        {
            UpdateParameters();
        }

#if UNITY_EDITOR
        void Update()
        {

            //Kobayashi
            if (dynamicRatio >= 1.0f)
                dynamicRatio = 1.0f;
            else if (dynamicRatio <= 0.0f)
                dynamicRatio = 0.0f;
            //Ebata
            UpdateParameters();

        }
#endif
        private void LateUpdate()
        {
            //Kobayashi
            if (dynamicRatio != 0.0f)
            {
                for (int i = 0; i < springBones.Count; i++)
                {
                    if (springBones[i].enabled && dynamicRatio > springBones[i].threshold)
                    {
                        springBones[i].UpdateSpring();
                    }
                }
            }
        }

        private void UpdateParameters()
        {
            UpdateParameter("pullForce", pullForce, pullCurve);
            UpdateParameter("stiffnessForce", stiffnessForce, stiffnessCurve);
            UpdateParameter("dragForce", dragForce, dragCurve);
            UpdateParameter("boneAxis", boneAxis);
            UpdateParameter("colliders", colliders);
            UpdateParameter("gravity", gravity);
        }
        private void UpdateParameter<T>(string fieldName, T baseValue)
        {
            var prop = springBones[0].GetType().GetField(fieldName, System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);

            for (int i = 0; i < springBones.Count; i++)
            {
                //Kobayashi
                if (!springBones[i].isUseEachBoneForceSettings)
                {
                    prop.SetValue(springBones[i], baseValue);
                }
            }
        }
        private void UpdateParameter(string fieldName, float baseValue, AnimationCurve curve)
        {
#if UNITY_EDITOR
            var start = curve.keys[0].time;
            var end = curve.keys[curve.length - 1].time;
            //var step	= (end - start) / (springBones.Length - 1);

            var prop = springBones[0].GetType().GetField(fieldName, System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);

            for (int i = 0; i < springBones.Count; i++)
            {
                //Kobayashi
                if (!springBones[i].isUseEachBoneForceSettings)
                {
                    var scale = curve.Evaluate(start + (end - start) * ((i + 1) / springBones.Count));
                    prop.SetValue(springBones[i], baseValue * scale);
                }
            }
#endif
        }
    }
}